home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 123_01.zip / AR1.BDS < prev    next >
Text File  |  1993-06-07  |  14KB  |  790 lines

  1. /*
  2.     archive - BDS C version
  3.  
  4.     translated from Software Tools ar/ver1.rat by:
  5.  
  6.         Oscar Goldman
  7.         1221 Knox Road
  8.         Wynnewood, PA 19096
  9.  
  10.     converted to use BDS C library by:
  11.  
  12.         Edward K. Ream
  13.         1850 Summit Ave.
  14.         Madison, WI 53705
  15.         (608) 231 -2952
  16.  
  17.     version: May 5, 1982; February 24, 1983
  18. */
  19.  
  20. #include "bdscio.h"
  21. #include "dio.h"
  22. #include "date.h"
  23.  
  24.  
  25. #define MAXLINE 300        /*  maximum line size */
  26. #define MAXCHARS 30
  27. #define NEWLINE '\n'
  28. #define EOS 0
  29. #define YES 1
  30. #define NO 0
  31.  
  32. #define    MAXFILES  100        /*  maximum number of files processable */
  33. #define SYS_MAXFN 15
  34.  
  35. #define    DELETE_CMD    'd'    /*  delete member from archive */
  36. #define    PRINT_CMD    'p'    /*  print archive members */
  37. #define    TABLE_CMD    't'    /*  print table of contents */
  38. #define    UPDATE_CMD    'u'    /*  update archive member */
  39. #define    VERBOSE_CMD    'v'    /*  controls amount of output */
  40. #define    EXTRACT_CMD    'x'    /*  extract archive member */
  41.  
  42. #define    USAGE_MESSAGE  "usage: ar1 [-](dptux)[v] archive [files]\n"
  43.  
  44. #define    HEADER_STRING  "#-h-"
  45. #define    TRAILER_STRING "#-t-"
  46. #define    NAMESIZE  20        /*  size of name allowed in header */
  47.  
  48. /*
  49.     The following depend on a properly defined notion of file type.
  50.     All strings should be the same length.
  51. */
  52.  
  53. #define    ASCII_STRING   "ascii "
  54. #define    LOCAL_STRING   "local "
  55. #define    BINARY_STRING  "binary"
  56. #define    ASCII          0
  57. #define    LOCAL          1
  58. #define    BINARY         2    
  59.  
  60.  
  61. /*
  62.     The file size (in chars) is computed for storage in the 
  63.     archive headers, although this information is not used.
  64. */
  65.  
  66. /*   GLOBAL VARIABLES    */
  67.  
  68. char *fname [MAXFILES];            /* list of file names        */
  69. int   fstat [MAXFILES];            /* status of each name in list    */
  70. int   fcount;                /* number of files on the list    */
  71.  
  72. char  chead [MAXLINE];            /* current header        */
  73.  
  74. int   errcnt;                /* error count            */
  75. int   verbose;                /* YES if verbose flag on    */
  76.  
  77.  
  78. main (argc,argv)
  79. int  argc;
  80. char **argv;
  81. {
  82.     _allocp = NULL;
  83.     dioinit(&argc, argv);
  84.     main1(argc, argv);
  85.     dioflush();
  86. }
  87.  
  88. main1(argc, argv)
  89. int argc;
  90. char **argv;
  91. {
  92.     char *archive, *command;
  93.     int i;
  94.  
  95.     /* initialize global error count */
  96.     errcnt = 0;
  97.  
  98.     /* make sure there is at least a command and an archive name */
  99.     if (argc < 3) {
  100.         fprintf(STD_ERR, "too few arguments\n");
  101.         error (USAGE_MESSAGE);
  102.     }
  103.  
  104.     /*
  105.         Put a list of file names into fnames [].
  106.         Check for duplicates.
  107.     */
  108.     get_fnames(argc, argv);
  109.  
  110.     /* point at the name of the archive */
  111.     archive = argv [2];
  112.     upper (archive);
  113.  
  114.     /* point at the options list */
  115.     command = argv [1];
  116.     lower (command);
  117.  
  118.     /* skip leading '-' if present */
  119.     if (command [0] == '-') {
  120.         i = 1;
  121.     }
  122.     else {
  123.         i = 0;
  124.     }
  125.  
  126.     if (command [i + 1] == VERBOSE_CMD) {
  127.         verbose = YES;
  128.     }
  129.     else if (command [i + 1] == EOS) {
  130.         verbose = NO;
  131.     }
  132.     else {
  133.         fprintf(STD_ERR, "option too long\n");
  134.         error (USAGE_MESSAGE);
  135.     }
  136.  
  137.     if (command [i] == UPDATE_CMD) {
  138.         update (archive);
  139.     }
  140.     else if (command [i] == TABLE_CMD) {
  141.         table (archive);
  142.     }
  143.     else if (command [i] == EXTRACT_CMD || command [i] == PRINT_CMD) {
  144.         extract (archive, command [i]);
  145.     }
  146.     else if (command [i] == DELETE_CMD) {
  147.         delete (archive);
  148.     }
  149.     else {
  150.         fprintf(STD_ERR, "unknown option\n");
  151.         error (USAGE_MESSAGE);
  152.     }
  153. }
  154.  
  155.  
  156. /* Add file 'name' to archive open on 'fd' */
  157.  
  158. add_file (name, fd)
  159. char *name;
  160. int fd;
  161. {
  162.     char head [MAXLINE], trail[MAXLINE];
  163.     int nfd;
  164.     char nfbuf [BUFSIZ];
  165.  
  166.     /* kludge for BDS C fopen */
  167.     nfd = nfbuf;
  168.  
  169.     if (fopen (name, nfbuf) == ERROR) {
  170.         fprintf(STD_ERR, "can't add %s\n", name);
  171.         errcnt++;
  172.         return;
  173.     }
  174.  
  175.     if (errcnt == 0) {
  176.         make_header (head, name);
  177.         if (verbose == YES) {
  178.             fprintf(STD_OUT, "%s\n", name);
  179.         }
  180.         put_line (head, fd);
  181.         copy_in (nfd, fd);
  182.         make_trailer (head, trail);
  183.         put_line (trail, fd);
  184.     }
  185.     fclose (nfd);
  186. }
  187.  
  188.  
  189. /*
  190.     Copy a file into an archive.
  191.     May have to be adjusted to allow for binary files.
  192. */
  193.  
  194. copy_in (fd, afd)
  195. int fd, afd;
  196. {
  197.     int c;
  198.  
  199.     while (1) {
  200.         /* allow abort with ^C from console */
  201.         chkkey();
  202.  
  203.         c = getc(fd);
  204.         if (c == ERROR || c == CPMEOF) {
  205.             break;
  206.         }
  207.         putc (c, afd);
  208.     }
  209. }
  210.  
  211.  
  212. /* Copy archive element from one archive to another */
  213.  
  214. copy_ele (oldafd, newafd)
  215. int oldafd, newafd;
  216. {
  217.     char line [MAXLINE];
  218.  
  219.     while (get_line (line, oldafd) != 0) {
  220.         put_line (line, newafd);
  221.         if (ele_end (line) == YES) {
  222.             return;
  223.         }
  224.     }
  225.     remark ("archive integrity in doubt - missing trailer.\n");
  226.     errcnt++;
  227. }
  228.  
  229.  
  230. /* Copy a file out of an archive */
  231.  
  232. copy_out (afd, fd)
  233. int afd, fd;
  234. {
  235.     char line [MAXLINE];
  236.     int  start;
  237.  
  238.     while (get_line (line, afd) != 0) {
  239.         if (ele_end (line) == YES) {
  240.             /*  we've copied the whole archive element */
  241.             return;
  242.         }
  243.         else {
  244.             put_line (line, fd);  /*  ordinary text */
  245.         }
  246.     }
  247.     remark ("archive integrity in doubt - missing trailer.\n");
  248.     errcnt++;
  249. }
  250.  
  251.  
  252. /* Delete files from the archive */
  253.  
  254. delete (aname)
  255. char *aname;
  256. {
  257.     int  tprefx;
  258.     char  tname [SYS_MAXFN];
  259.     int afd, tfd;
  260.     char afbuf [BUFSIZ], tfbuf[BUFSIZ];
  261.  
  262.     /* kludge for BDS C fopen, fcreat */
  263.     afd = afbuf;
  264.     tfd = tfbuf;
  265.  
  266.     tprefx = 0;
  267.     if (fcount <= 0) {
  268.         error ("delete by name only.\n");
  269.     }
  270.     if (fopen (aname, afbuf) == ERROR) {
  271.         cant (aname);
  272.     }
  273.  
  274.     mkunik (tprefx, tname); 
  275.     if (fcreat (tname, tfbuf) == ERROR) {
  276.         fprintf(STD_ERR, "can not create %s\n", tname);
  277.     }
  278.  
  279.     replace (afd, tfd, DELETE_CMD);
  280.     not_found ();
  281.  
  282.     fclose (afd);
  283.     putc (CPMEOF, tfd);
  284.     fflush (tfd);
  285.     fclose (tfd);
  286.     if (errcnt == 0) {
  287.         unlink (aname);
  288.         rename (tname,aname);
  289.     }
  290.     else {
  291.         remark ("fatal errors - archive not altered.\n");
  292.     }
  293.     unlink (tname);
  294. }
  295.  
  296.  
  297. /* Extract files from archive */
  298.  
  299. extract (archive, cmd)
  300. char *archive, cmd;
  301. {
  302.     char name [SYS_MAXFN], hdr[MAXLINE];
  303.     int afd, fd;
  304.     char    afbuf [BUFSIZ], fbuf[BUFSIZ];
  305.  
  306.     /* kludge for BDS C fopen, fcreat */
  307.     afd = afbuf;
  308.     fd  = fbuf;
  309.  
  310.     if (fopen (archive, afbuf) == ERROR) {
  311.         fprintf(STD_ERR, "can not open archive: %s\n", archive);
  312.         exit();
  313.     }    
  314.  
  315.     /* NOTE:  this code could be much improved by keeping track of the
  316.      *      number of files that have been extracted and exiting
  317.      *      when all have been found.
  318.      */
  319.  
  320.     while (get_header (afd, hdr, name) != EOF) {
  321.  
  322.         if (file_arg (name) == NO) {
  323.             skipf (afd);
  324.         }
  325.         else {
  326.             if (verbose == YES && cmd == PRINT_CMD) {
  327.                 fprintf(STD_OUT, "%s\n", name);
  328.             }
  329.             else if (verbose == YES) {
  330.                 fprintf(STD_OUT, "%s\n", name);
  331.             }
  332.  
  333.             if (cmd == PRINT_CMD) {
  334.                 copy_out (afd, STD_OUT);
  335.             }
  336.             else {
  337.                 if (fcreat (name, fbuf) != ERROR) {
  338.                     copy_out (afd, fd);
  339.                     putc (CPMEOF, fd);
  340.                     fflush (fd);
  341.                     fclose (fd);
  342.                 }
  343.                 else {
  344.                     fprintf(STD_ERR,
  345.                         "can not create %s\n", name);
  346.                     errcnt++;
  347.                     skipf (afd);
  348.                 }
  349.             }
  350.  
  351.         }
  352.     }
  353.     not_found();
  354. }
  355.  
  356.  
  357. /* See if name is present in argument list */
  358.  
  359. file_arg (name)
  360. char *name;
  361. {
  362.     int i;
  363.  
  364.     /* a null list matches ALL files */
  365.     if (fcount <= 0) {
  366.         return (YES);
  367.     }
  368.  
  369.     for (i = 0; i < fcount; i++) {
  370.         if (strcmp (name, fname [i]) == 0) {
  371.             fstat [i] = YES;
  372.             return (YES);
  373.         }
  374.     }
  375.     return (NO);
  376. }
  377.  
  378.  
  379. /* Determine size of file (in chars) */
  380.  
  381. unsigned
  382. fsize (name)
  383. char *name;
  384. {
  385.     int fd;
  386.     char fbuf [BUFSIZ];
  387.     unsigned count;
  388.     char line [MAXLINE];
  389.     int n;
  390.  
  391.     /* kludge for BDS C fopen */
  392.     fd = fbuf;
  393.  
  394.     if (fopen (name, fbuf) == ERROR) {
  395.         return (ERROR);
  396.     }
  397.  
  398.     count = 0;
  399.     while (n = get_line(line, fd)) {
  400.         count += n;
  401.     }
  402.  
  403.     fclose (fd);
  404.     return (count);
  405. }
  406.  
  407.  
  408. /*
  409.     Get file names into 'fname', check for duplicates.
  410.     File names are stored LOWER CASE.
  411. */
  412.  
  413. get_fnames(argc, argv)
  414. int argc;
  415. char **argv;
  416. {
  417.     int ap, fp, len, i;
  418.     char line [MAXLINE];
  419.  
  420.     for (fp = 0, ap = 3; ap < argc; ap++) {
  421.  
  422.         fname [fp] = argv[ap];
  423.         if (fname [fp][0] == '-' && fname [fp][1] == EOS) {
  424.             
  425.             while (fp < MAXFILES) {
  426.                 /* get list from standard input */
  427.  
  428.                 len = get_line (line, STD_IN);
  429.                 if (len <= 1) {
  430.                     break;
  431.                 }
  432.                 /* remove the NEWLINE */
  433.                 line [len-1] =EOS;
  434.  
  435.                 /* save it in dynamic storage */
  436.                 fname [fp] = strsav (line);
  437.                 lower (fname [fp]);
  438.                 fp++;
  439.                 if (fp >= MAXFILES) {
  440.                     error("too many file names\n");
  441.                 }
  442.             }
  443.         }
  444.         else {
  445.             lower (fname [fp++]);
  446.             if (fp >= MAXFILES) {
  447.                 error ("too many file names.\n");
  448.             }
  449.         }
  450.     }
  451.  
  452.     /* set global count of the number of files. */
  453.     fcount = fp;
  454.     for (fp = 0; fp < fcount; fp++) {
  455.         fstat [fp] = NO;
  456.     }
  457.  
  458.     for (fp = 0; fp < fcount-1; fp++) {
  459.         for (i = fp + 1; i < fcount; i++) {
  460.             if (strcmp (fname [fp], fname [i]) == 0) {
  461.                 fprintf(STD_ERR,
  462.                     "duplicate %s\n", fname [i]);
  463.                 errcnt++;
  464.             }
  465.         }
  466.     }
  467.     if (errcnt != 0) {
  468.         error ("fatal errors - archive not altered.\n");
  469.     }
  470. }
  471.  
  472.  
  473. /* Get header information from archive member in 'fd' */
  474.  
  475. get_header (fd, hdr, name)
  476. int fd;
  477. char *hdr, *name;
  478. {
  479.     char text [SYS_MAXFN],*hdrstr;
  480.     int index;
  481.  
  482.     hdrstr = HEADER_STRING;
  483.  
  484.     if (get_line (hdr, fd) == 0) {
  485.         return (EOF);
  486.     }
  487.  
  488.     /* keep file names in LOWER case in header, trailer */
  489.     lower (hdr);
  490.  
  491.     index = getwrd (hdr, text);
  492.     if (strcmp (text, hdrstr) != 0) {
  493.         remark ("archive not in proper format.\n");
  494.         errcnt++;
  495.         return (EOF);
  496.     }
  497.  
  498.     save_header (hdr);
  499.     getwrd (hdr + index, name);
  500.     return (YES);
  501. }
  502.  
  503.  
  504. /*
  505.     Determine file type (ASCII, LOCAL, or BINARY).
  506.     There is no straight-forward way to do this in CP/M.
  507. */
  508.  
  509. get_ftype (name)
  510. char *name;
  511. {
  512.     return (ASCII);
  513. }
  514.  
  515.  
  516. /* Make header line for an archive member */
  517.  
  518. make_header (head, name)
  519. char *head, *name;
  520. {
  521.     int  type, length;
  522.     char size [20], *now;
  523.  
  524.     strcpy (head, HEADER_STRING);
  525.     strcat (head, "  ");
  526.     strcat (head, name);
  527.  
  528.     for (length = strlen(name) + 1; length <= NAMESIZE; length++) {
  529.         strcat (head, " ");
  530.     }
  531.  
  532.     sprintf(size, "%11d", fsize(name));
  533.     strcat (head, size);
  534.     strcat (head, "  ");
  535.  
  536.     type = get_ftype (name);
  537.     if (type == ASCII) {
  538.         strcat (head, ASCII_STRING);
  539.     }
  540.     else if (type == LOCAL) {
  541.         strcat (head, LOCAL_STRING);
  542.     }
  543.     else if (type == BINARY) {
  544.         strcat (head, BINARY_STRING);
  545.     }
  546.     else {
  547.         strcat (head, ASCII_STRING);
  548.     }
  549.  
  550.     strcat (head, "  ");
  551.     now = getnow();
  552.     strcat (head, now);
  553.     strcat (head, "\n");
  554. }
  555.  
  556.  
  557. /* Make trailer line for an archive member */
  558.  
  559. make_trailer (head, trail)
  560. char *trail, *head;
  561. {
  562.     int index;
  563.  
  564.     /* skip over header string */
  565.     index = getwrd (head, trail);
  566.  
  567.     strcpy (trail, TRAILER_STRING);
  568.     strcat (trail, head + index);
  569. }
  570.  
  571.  
  572. /* Print 'not found' message if member isn't in archive */
  573.  
  574. not_found()
  575. {
  576.     int i;
  577.  
  578.     for (i = 0; i < fcount; i++) {
  579.         if (fstat [i] == NO) {
  580.             fprintf(STD_ERR, "%s not in archive.\n", fname [i]);
  581.             errcnt++;
  582.         }
  583.     }
  584. }
  585.  
  586.  
  587. /* See if string is end of archive element */
  588.  
  589. ele_end (str)
  590. char *str;
  591. {
  592.     int i;
  593.     char *tstr;
  594.  
  595.     /* look for trailer string */
  596.     tstr = TRAILER_STRING;
  597.     for (i=0; tstr [i] != EOS; i++) {
  598.         if (tstr [i] != str[i]) {
  599.             return(NO);
  600.         }
  601.     }
  602.  
  603.     /* compare str against name in the trailer */
  604.     str = skipbl (str + i);
  605.     if (strcmp(str, chead) ==  0) {
  606.         return YES;
  607.     }
  608.     else {
  609.         return NO;
  610.     }
  611. }
  612.  
  613.  
  614. /* Replace or delete archive members */
  615.  
  616. replace (afd, tfd, cmd)
  617. int afd, tfd;
  618. char cmd;
  619. {
  620.     char hdr [MAXLINE], name[SYS_MAXFN];
  621.  
  622.     while (get_header (afd, hdr, name) != EOF) {
  623.         if (file_arg (name) == YES) {
  624.             if (cmd == UPDATE_CMD) {
  625.                 add_file (name, tfd);
  626.             }
  627.             if (verbose == YES && cmd == DELETE_CMD) {
  628.                 fprintf(STD_OUT, "%s\n", name);
  629.             }
  630.             skipf (afd);
  631.         }
  632.         else {
  633.             /* just copy.  make no change */
  634.             fprintf(tfd, "%s", hdr);
  635.             copy_ele (afd, tfd);
  636.         }
  637.     }
  638. }
  639.  
  640.  
  641. /* Save current header in the global array chead [] */
  642.  
  643. save_header (head)
  644. char *head;
  645. {
  646.     int index;
  647.  
  648.     /* skip header string */
  649.     index = getwrd (head, chead);
  650.     head = skipbl (head + index);
  651.     strcpy (chead, head);
  652. }
  653.  
  654.  
  655. /* Skip current archive element on file afd */
  656.  
  657. skipf (afd)
  658. int afd;
  659. {
  660.     char line [MAXLINE];
  661.  
  662.     while (get_line (line, afd) != 0) {
  663.         if (ele_end (line) == YES) {
  664.             return;
  665.         }
  666.     }
  667.     remark ("archive integrity in doubt - missing trailer.\n");
  668.     errcnt++;
  669. }
  670.  
  671.  
  672. /* Print table of archive contents */
  673.  
  674. table (aname)
  675. char *aname;
  676. {
  677.     int afd;
  678.     char    afbuf [BUFSIZ];
  679.     char hdr [MAXLINE], name[SYS_MAXFN];
  680.  
  681.     /* kludge for BDS C fopen */
  682.     afd = afbuf;
  683.  
  684.     if (fopen (aname, afbuf) == ERROR) {
  685.         cant (aname);
  686.     }
  687.  
  688.     while (get_header (afd, hdr, name) != EOF) {
  689.         if (file_arg (name) == YES) {
  690.             tprint (hdr);
  691.         }    
  692.         skipf (afd);
  693.     }
  694.  
  695.     fclose (afd);
  696.     not_found();
  697. }
  698.  
  699.  
  700. /* Print table entry for one archive member */
  701.  
  702. tprint (hdr)
  703. char *hdr;
  704. {
  705.     char name [SYS_MAXFN];
  706.     int index;
  707.  
  708.     /* skip over the header string */
  709.     index = getwrd (hdr, name);
  710.  
  711.     /* put file name in name [], point i past name */
  712.     index += getwrd (hdr + index, name);
  713.  
  714.     /* print the name */
  715.     fprintf(STD_OUT, "%s", name);
  716.  
  717.     /* print other info from header only in verbose mode */
  718.     if (verbose == YES) {
  719.         for (; hdr [index] != NEWLINE && hdr [index] != EOS; index++) {
  720.             putc (hdr [index], STD_OUT);
  721.         }
  722.     }
  723.  
  724.     /* end the line of information */
  725.     putc (NEWLINE, STD_OUT);
  726. }
  727.  
  728.  
  729. /* Update existing files, add new ones at end */
  730.  
  731. update (aname)
  732. char *aname;
  733. {
  734.     int afd, tfd;
  735.     char    afbuf [BUFSIZ], tfbuf[BUFSIZ];
  736.     int fp;
  737.     int tprefx;
  738.     char  tname [SYS_MAXFN];
  739.  
  740.     /* kludge for BDS C fopen, fcreat routines */
  741.     afd = afbuf;
  742.     tfd = tfbuf;
  743.  
  744.     tprefx = 0;
  745.     if (fopen (aname, afbuf) == ERROR) {
  746.         /*  try to create a new archive */
  747.         if (fcreat (aname, afbuf) == ERROR) {
  748.             fprintf(STD_ERR, "can not create %s\n", aname);
  749.         }
  750.         putc(CPMEOF, afd);
  751.         fflush(afd);
  752.         fclose(afd);
  753.         if (fopen(aname, afbuf) == ERROR) {
  754.             cant(aname);
  755.         }
  756.     }
  757.     mkunik (tprefx, tname);
  758.     if (fcreat (tname, tfbuf) == ERROR) {
  759.         fprintf(STD_ERR, "can not create %s\n", tname);    
  760.     }
  761.  
  762.     /* update existing members */
  763.     replace (afd, tfd, UPDATE_CMD);
  764.  
  765.     /* add new members */
  766.     for (fp = 0; fp < fcount; fp++) {
  767.         if (fstat [fp] == NO) {
  768.             add_file (fname [fp], tfd);
  769.             fstat [fp] = YES;
  770.         }
  771.     }
  772.     fclose (afd);
  773.     putc (CPMEOF, tfd);
  774.     fflush (tfd);
  775.     fclose (tfd);
  776.  
  777.     if (errcnt == 0) {
  778.         unlink (aname);
  779.         rename (tname,aname);
  780.     }
  781.     else {
  782.         remark ("fatal errors - archive not altered.\n");
  783.         unlink (tname);
  784.     }
  785. }
  786. (aname);
  787.         rename (tname,aname);
  788.     }
  789.     else {
  790.         re